﻿/*****************************************************************************
 * Hyldahl.Services.TaskProcessing                 Created by: MSH 2008.07.22
 * --------------------------------------------------------------------------
 * FileName: Workers\TaskProcessingWorker.cs
 * --------------------------------------------------------------------------
 * Copyright 2009 Martin Sixhøj Hyldahl
 *****************************************************************************/

using System;
using System.Threading;
using System.Diagnostics;

namespace Hyldahl.Services.TaskProcessing.Workers
{
    public class TaskProcessingWorker : Worker
    {
        /*****************************************************
         * CONSTRUCTOR
         *****************************************************/

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskProcessingWorker"/> class.
        /// </summary>
        /// <param name="controller">The controller.</param>
        /// <param name="name">The name.</param>
        public TaskProcessingWorker(TaskProcessingController controller, string name)
            : base(controller, name)
        {
        }

        /*****************************************************
         * PRIVATE METHODS
         *****************************************************/

        /// <summary>
        /// Worker thread.
        /// </summary>
        protected override void WorkerThreadStart()
        {
            try
            {
                this.TraceSource.TraceInformation("{0}: Starting thread", this.Name);

                Stopwatch stopwatch = new Stopwatch();

                while (true)
                {
                    Task task = null;

                    // Get unprocessed task
                    try
                    {
                        task = this.Controller.Context.DataStore.GetUnProcessedTask();
                    }
                    catch (Exception ex)
                    {
                        this.TraceSource.TraceEvent(TraceEventType.Error, 1, "{0}: Could not get unprocessed task: {1}", this.Name, ex.Message);
                    }

                    if (task != null)
                    {
                        if (this.StopFlag)
                            break;

                        try
                        {
                            this.TraceSource.TraceInformation("{0}: Getting task processor for task type: {1}", this.Name, task.TaskType);

                            TaskProcessor taskProcessor = this.Controller.Context.TaskProcessorPlugins.GetTaskProcessor(task.TaskType);

                            // PROCESS TASK

                            stopwatch.Reset();
                            stopwatch.Start();

                            DateTime startProcessingDate = DateTime.UtcNow;

                            if (taskProcessor != null)
                            {
                                this.TraceSource.TraceInformation("{0}: Processing task.", this.Name);

                                try
                                {
                                    taskProcessor.Process(task);
                                }
                                catch (Exception ex)
                                {
                                    task.CompletedSuccessfully  = false;
                                    task.ResultData             = string.Format("{0}\n{1}", ex.Message, ex.StackTrace);
                                }

                                this.TraceSource.TraceData(TraceEventType.Verbose, 1, "Task Data: " + task.Data);
                                this.TraceSource.TraceData(TraceEventType.Verbose, 2, "Result Data: " + task.ResultData);
                                this.TraceSource.TraceData(TraceEventType.Verbose, 3, "CompletedSuccessfully: " + task.CompletedSuccessfully.ToString());
                            }
                            else
                            {
                                task.CompletedSuccessfully  = false;
                                task.ResultData             = "No task processor for this task type.";
                            }

                            task.ProcessingTime     = stopwatch.ElapsedMilliseconds;
                            task.CompletedDate      = DateTime.UtcNow;
                            task.IsProcessed        = true;

                            stopwatch.Stop();

                            this.TraceSource.TraceInformation("{0}: Task processed in {1} ms.", this.Name, task.ProcessingTime);

                            // SAVE TASK RESULTS

                            this.TraceSource.TraceInformation("{0}: Saving processing result for task: {1}", this.Name, task.Id);

                            try
                            {
                                this.Controller.Context.DataStore.SaveTaskResult(task);
                            }
                            catch (Exception ex)
                            {
                                this.TraceSource.TraceEvent(TraceEventType.Error, 1, "{0}: Could not save task results: {1} - {2} - {3}", this.Name, task.Id, task.TaskType, ex.Message);
                            }
                        }
                        catch (Exception ex)
                        {
                            this.TraceSource.TraceEvent(TraceEventType.Error, 1, "{0}: Could not process task: {1} - {2} - {3}", this.Name, task.Id, task.TaskType, ex.Message);
                        }

                        if (this.StopFlag)
                            break;
                    }
                    
                    DateTime timeout = DateTime.Now.AddMilliseconds(50);

                    while (DateTime.Now < timeout && !this.StopFlag)
                    {
                        Thread.Sleep(200);
                    }

                    if (this.StopFlag)
                        break;
                }
            }
            catch (Exception ex)
            {
                this.TraceSource.TraceEvent(TraceEventType.Error, 2, "{0}: Failure - {1}", this.Name, ex.Message);
            }

            this.State = WorkerState.Stopped;

            this.TraceSource.TraceInformation("{0}: Stopped", this.Name);
        }
    }
}